后缀式的特点可用于计算表达式的值,我们通过中缀转后缀的方式可以将原表达式重新排列组合成为计算机易于理解的计算方式。
详情请参考:逆波兰算法(后缀表达式)
关于中缀转后缀
中缀式转后缀式 如:
1+2就是一个中缀式,转换成后缀式为1 2 +
1+2*3…… ……1 2 3 * +
1+(2+5)…… ……1 2 5 + +
在计算时,从最左侧开始先选定一个符号与该符号左边的两个数结合运算。以下(黄色高亮部分)计算过程如下
1与2进行+运算
- 1+2*3…… ……1 2 3 * +
1. 最左边的符号 * ,左侧的两个数 2 3计算:2*3 = 6表达式:1 6 +
2. 最左边的符号 + ,左侧的两个数 1 6计算:1+6 = 7
- 1+(2+5)…… ……1 2 5 + +
3. ...计算:2+5=7表达式:1 7 +
4. ...计算:1+7=8
如上所示,使用后缀式可以清晰的表示出表达式中的运算关系,所有运算符符号中,优先级最高的在最左边。
计算时从最左侧的符号先开始,且每个符号都与它左侧最近的两个数据结合。
可以说,后缀式就是根据计算表达式中的优先级进行设计的。
比如,在计算表达式中 ’ ( ) ’ 的优先级最高,因此在转后缀式时遇到 ‘(’ 与 ‘)’ 之间的符号就认为是优先级最高的符号。
eg: a*(b+c)
a b c + *过程详解:
1、===a*(b+c)===↑
后缀: a ✔
符号:
2、===a*(b+c)===↑
后缀: a
符号: * ✔
3、===a*(b+c)===↑
后缀: a
符号: * ( ✔
4、===a*(b+c)===↑
后缀: a b ✔
符号: * (
5、===a*(b+c)===↑
后缀: a b
符号: * ( + ✔
6、===a*(b+c)===↑
后缀: a b c ✔
符号: * ( +
7、===a*(b+c)===↑
后缀: a b c
符号: * ( + ) ✔
注:遇到')',后面进来的符号都视为较低优先级符号,因此把' ( ) '内的符号全部转移到后缀式中
8、=============
后缀: a b c + ✔
符号: *
9、=============
后缀: a b c + * ✔
符号:
中缀转后缀技巧
中缀转后缀的核心就是,将优先级高的运算放在最前边计算,如 … (b+c)… 形式的表达式 ,要变成 … b c + … 。后缀式中优先级体现在符号自左向右的顺序,表达式的关系体现在每个符号与其左边最近的两个数字。
而针对表达式 a+b-c ,因为 ‘+’ ‘-’ 优先级相同,而我们的计算顺序为同优先级自左向右,则我们认为左边的 ‘+’ 优先级更高。因此后缀式为 a b + c - ,其中 a b + 为(a+b) 就是原式中优先级高的部分。
而对于 a + b * c 的表达式,显然 b*c 的优先级最高,则后缀式为 a b c * + 。
在本例中,函数 void InfixToSuffix();
进行中缀转后缀计算。
中缀转后缀计算机代码
#include using std::cin;
using std::cout;
using std::endl;template<typename T>
class Stack
{
public:Stack(int _m_size &#61; 20) :m_size(_m_size), mtop(0){data &#61; new T[m_size]();}~Stack(){delete[] data;}bool empty(){return mtop &#61;&#61; 0;}void push(int val){if (Full()){throw std::exception("error: Stack is Full !");}data[mtop] &#61; val;mtop&#43;&#43;;}T top(){if (empty()){throw std::exception("error: The stack is empty !");}return data[mtop - 1];}void pop(){if (empty()){throw std::exception("error: Stack is Empty !");}mtop--;}void show(){if (empty()){cout << endl;}else{int i &#61; 0;while (i < mtop){cout << data[i] << " ";i&#43;&#43;;}cout << endl;}}
private:bool Full(){return mtop &#61;&#61; m_size;}T* data;int mtop;int m_size;
};
class Calculator
{
public:Calculator(int _m_size &#61; 40) :m_size(_m_size), m_result(0){m_str &#61; new char[_m_size &#43; 1]();}~Calculator(){delete[] m_str;}void setData(){cin.getline(m_str, m_size - 1); }void InfixToSuffix(); void Compure();double Getm_result(){return m_result;}
private:bool IsPop(char a, char b);char* m_str;double m_result;int m_size;};int main()
{while (1) {Calculator ca;ca.setData();ca.InfixToSuffix();ca.Compure();cout << ca.Getm_result() << endl;}return 0;
}
bool Calculator::IsPop(char a, char b)
{if (b &#61;&#61; &#39;(&#39;) return false; if (a &#61;&#61; &#39;*&#39; || a &#61;&#61; &#39;/&#39;){if (b &#61;&#61; &#39;&#43;&#39; || b &#61;&#61; &#39;-&#39;){return false;}else{ return true;}}return true;
}
void Calculator::InfixToSuffix()
{char* dst &#61; new char[m_size*2](); Stack<char> symbol; int i &#61; 0;int k &#61; 0;while (m_str[i] !&#61; &#39;\0&#39;){if (m_str[i] &#61;&#61; &#39; &#39;) {i&#43;&#43;;continue;}else if (m_str[i] &#61;&#61; &#39;(&#39;) {symbol.push(m_str[i]);}else if (m_str[i] &#61;&#61; &#39;)&#39;) {while (symbol.top() !&#61; &#39;(&#39;){dst[k&#43;&#43;] &#61; symbol.top();dst[k&#43;&#43;] &#61; &#39; &#39;;symbol.pop();}symbol.pop();}else if (isdigit(m_str[i])){dst[k&#43;&#43;] &#61; m_str[i];if (!isdigit(m_str[i &#43; 1])) {dst[k&#43;&#43;] &#61; &#39; &#39;;}}else{switch (m_str[i]){case &#39;&#43;&#39;:case &#39;-&#39;:case &#39;*&#39;:case &#39;/&#39;:if (symbol.empty()) {symbol.push(m_str[i]);}else {if (IsPop(m_str[i], symbol.top())) {dst[k&#43;&#43;] &#61; symbol.top();symbol.pop();continue;}else {symbol.push(m_str[i]);}}break;default:break;}}i&#43;&#43;; }while (!symbol.empty()){dst[k&#43;&#43;] &#61; symbol.top();symbol.pop();}dst[k] &#61; &#39;\0&#39;;
运行截图&#xff1a;
注&#xff1a;在计算器类中
Calculator(int _m_size &#61; 40) :m_size(_m_size), m_result(0)
{}
构造函数 _m_size 默认设置的为40&#xff0c;这将影响到我们输入的计算表达式的长度&#xff0c;我们在编译时可以根据需求自行更改代码。